home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_494 / vscreen / source / vscreen.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  14KB  |  448 lines

  1. /*
  2.  *  VSCREEN.C       Creates virtual screens that can be larger than
  3.  *                  the actual display area of your monitor.  The virtual
  4.  *                  screen scrolls when the mouse moves off the edge of
  5.  *                  the display.
  6.  *
  7.  *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
  8.  *
  9.  *                  You may distibute this code as is, for non-commercial
  10.  *                  purposes, provided that this notice remains intact and the
  11.  *                  documentation file is distributed with it.
  12.  *
  13.  *                  You may not modify this code nor incorporate it into your
  14.  *                  own programs without the permission of the author.
  15.  */
  16.  
  17. /*
  18.  *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
  19.  *  area of the IntuitionBase structure.  Use it at your own risk.  It is
  20.  *  likely to break under a future release of Intuition.
  21.  */
  22.  
  23. #include "vScreen.h"
  24.  
  25. static char *program = "vScreen";           /* the program name */
  26. static char *author  = COPYRIGHT;           /* the copyright notice */
  27. #define LOADVERS        1                   /* this program's version */
  28.  
  29. static char *handler = "L:vScreen-Handler"; /* the name of the handler */
  30. #define HANDLER         &(handler[2])       /* same but in the current dir */
  31.  
  32.  
  33. extern struct LayersBase *LayersBase;       /* the Layers library */
  34.  
  35. struct vScreenInfo *vScreenData;            /* data needed by the handler */
  36. struct Screen *VScreen = NULL;              /* the virtual screen */
  37. static long Segment = NULL;                 /* the loaded handler */
  38. SHORT ScreenWidth,ScreenHeight;             /* the new screen sizes */
  39.  
  40. static struct MsgPort *NamedPort = NULL;    /* used to find the handler later */
  41. static struct MsgPort *InputPort = NULL;    /* to talk to Input.Device */
  42. static struct IOStdReq *InputBlock = NULL;  /* IO block for Input.Device */
  43. static short  InputDevice = FALSE;          /* is Input.Device open? */
  44. static int    Enlarged = FALSE;             /* is screen changed? */
  45.  
  46.  
  47. /*
  48.  *  These routines are in vScreenSetup.c
  49.  */
  50.  
  51. extern struct Screen *FindScreen();
  52. extern void SetVariables();
  53. extern void GetVariables();
  54. extern int  EnlargeScreen();
  55. extern void RestoreScreen();
  56.  
  57.  
  58. #ifndef PROTO
  59. extern long SetFunction();
  60. #endif
  61.  
  62. /*
  63.  *  We trap these routines via SetFunction in order to make vSscreen work.
  64.  */
  65.  
  66. #ifndef PROTO
  67. extern void MoveSprite();
  68. extern void LoadView();
  69. extern void AutoRequest();
  70. extern void BuildSysRequest();
  71. extern void CloseScreen();
  72. #endif
  73.  
  74. extern long LVOMoveSprite;
  75. extern long LVOLoadView;
  76. extern long LVOAutoRequest;
  77. extern long LVOBuildSysRequest;
  78. extern long LVOCloseScreen;
  79.  
  80.  
  81. /*
  82.  *  CreateNonSigPort()
  83.  *
  84.  *  Creates a message port with signal type PA_IGNORE.  Based on
  85.  *  CreatePort() from the exec support functions documented in the RKM.
  86.  */
  87.  
  88. struct MsgPort *CreateNonSigPort(name,pri)
  89. char *name;
  90. BYTE pri;
  91. {
  92.    struct MsgPort *thePort;
  93.    
  94.    thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
  95.                                          MEMF_PUBLIC | MEMF_CLEAR);
  96.    if (thePort)
  97.    {
  98.       thePort->mp_Node.ln_Name = name;
  99.       thePort->mp_Node.ln_Pri  = pri;
  100.       thePort->mp_Node.ln_Type = NT_MSGPORT;
  101.       
  102.       thePort->mp_Flags = PA_IGNORE;
  103.       thePort->mp_SigBit = 0;
  104.       thePort->mp_SigTask = NULL;
  105.       
  106.       if (name)
  107.          AddPort(thePort);
  108.         else
  109.          NewList(&(thePort->mp_MsgList));
  110.    }
  111.    return(thePort);
  112. }
  113.  
  114.  
  115. /*
  116.  *  DeleteNonSigPort()
  117.  *
  118.  *  Deletes a message port with signal type PA_IGNORE.  Based on
  119.  *  DeletePort() from the exec support functions documented in the RKM
  120.  */
  121.  
  122. void DeleteNonSigPort(thePort)
  123. struct MsgPort *thePort;
  124. {
  125.    if (thePort->mp_Node.ln_Name) RemPort(thePort);
  126.    thePort->mp_Node.ln_Type = 0xFF;
  127.    thePort->mp_MsgList.lh_Head = (struct Node *) -1;
  128.    FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
  129. }
  130.  
  131.  
  132. /*
  133.  *  DoExit()
  134.  *
  135.  *  Exit with error status.  Print a message with up to three parameters
  136.  *  and then clean up everything (restore the screen if it is enlarged,
  137.  *  unload the handler if it is loaded, close the Input.Device and free
  138.  *  its IO blocks and ports, and close any open libraries).  Return the
  139.  *  error status.
  140.  */
  141.  
  142. void DoExit(s,x1,x2,x3)
  143. char *s, *x1,*x2,*x3;
  144. {
  145.    int status = OK_EXIT;
  146.  
  147.    if (s)
  148.    {
  149.       printf(s,x1,x2,x3);
  150.       printf("\n");
  151.       status = ERROR_EXIT;
  152.    }
  153.    if (Enlarged)        RestoreScreen();
  154.    if (NamedPort)       DeleteNonSigPort(NamedPort);
  155.    if (Segment)         UnLoadSeg(Segment);
  156.    if (InputDevice)     CloseDevice(InputBlock);
  157.    if (InputBlock)      DeleteStdIO(InputBlock);
  158.    if (InputPort)       DeletePort(InputPort);
  159.    if (IntuitionBase)   CloseLibrary(IntuitionBase);
  160.    if (GfxBase)         CloseLibrary(GfxBase);
  161.    if (LayersBase)      CloseLibrary(LayersBase);
  162.    exit(status);
  163. }
  164.  
  165.  
  166. /*
  167.  *  CheckLibOpen()
  168.  *
  169.  *  Call OpenLibrary() for the specified library, and check that the 
  170.  *  open succeeded.
  171.  */
  172.  
  173. void CheckLibOpen(lib,name,rev)
  174. APTR *lib;
  175. char *name;
  176. int rev;
  177. {
  178.    #ifndef PROTO
  179.    extern APTR OpenLibrary();
  180.    #endif
  181.    
  182.    if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
  183.       DoExit("Can't open '%s'",name);
  184. }
  185.  
  186.  
  187. /*
  188.  *  GetInt()
  189.  *
  190.  *  Read the first integer from the given string variable (used to parse
  191.  *  the command-line arguments).  If no integer can be read, exit and
  192.  *  show the usage string.
  193.  */
  194.  
  195. static long GetInt(s)
  196. char *s;
  197. {
  198.    long i;
  199.  
  200.    if (sscanf(s,"%ld",&i) != 1) DoExit("Usage:  %s",USAGE);
  201.    return(i);
  202. }
  203.  
  204.  
  205. /*
  206.  *  ParseArguments()
  207.  *
  208.  *  Parse the command-line arguments.  If there are too many or too few
  209.  *  arguments, exit with an error message, otherwise get the width and height
  210.  *  agruments.  If there was a screen name specified, record that.
  211.  *  Find the specified screen.
  212.  */
  213.  
  214. static void ParseArguments(argc,argv)
  215. int argc;
  216. char *argv[];
  217. {
  218.    char *ScreenName = NULL;
  219.  
  220.    if (argc < 3) DoExit("Width and Height are required\nUsage:  %s",USAGE);
  221.    if (argc > 4) DoExit("Too many arguments");
  222.    ScreenWidth  = GetInt(argv[1]);
  223.    ScreenHeight = GetInt(argv[2]);
  224.    if (ScreenWidth <= 0 || ScreenHeight <= 0)
  225.       DoExit("Screen height and width must be positive");
  226.    if (ScreenWidth > 1024 || ScreenHeight > 1024)
  227.       printf("Warning:  sizes greater than 1024 may cause Blitter problems\n");
  228.    if (argc > 3 && argv[3] && argv[3][0] != '\0') ScreenName = argv[3];
  229.    VScreen = FindScreen(ScreenName);
  230. }
  231.  
  232.  
  233. /*
  234.  *  LoadHandler()
  235.  *
  236.  *  Try to LoadSeg the handler from the current directory, and if it is not
  237.  *  found, try the L: directory.  If neither can be loaded, exit with a 
  238.  *  message.  Once the handler is loaded, call its Setup routine passing it
  239.  *  our version number.  The handler will check the versions for compatability,
  240.  *  and return NULL for version mismatch, or a pointer to its data structure
  241.  *  with pointers to the variables that vScreen will initialize for it.
  242.  *  LoadHandler() sets the pointer to the handlers SegList, and sets the
  243.  *  loader version number
  244.  */
  245.  
  246. static void LoadHandler()
  247. {
  248.    struct vScreenInfo *(*Setup)();
  249.  
  250.    if ((Segment = LoadSeg(HANDLER)) == NULL)
  251.       if ((Segment = LoadSeg(handler)) == NULL)
  252.          DoExit("Can't Load '%s'",handler);
  253.    Setup = (struct vScreenInfo *(*)()) ((Segment << 2) + 4);
  254.    
  255.    vScreenData   = (*Setup)(LOADVERS);
  256.    if (vScreenData)
  257.    {
  258.       if (var(MajVers) > 1) DoExit("version mismatch with '%s'",HANDLER);
  259.    } else {
  260.       DoExit("'%s' reports a version mismatch",HANDLER);
  261.    }
  262.  
  263.    var(Segment)  = Segment;
  264.    var(LoadVers) = LOADVERS;
  265. }
  266.  
  267.  
  268. /*
  269.  *  TellInputDevice()
  270.  *
  271.  *  Create a port and I/O block, then open the input device.  Set up the
  272.  *  I/O block to add or remove the input handler, and send the request
  273.  *  to the input device.  Finally, close the device and delete the
  274.  *  I/O block and port.
  275.  */
  276.  
  277. void TellInputDevice(function)
  278. int function;
  279. {
  280.    long status;
  281.  
  282.    if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
  283.    if ((InputBlock = CreateStdIO(InputPort)) == NULL)
  284.       DoExit("Can't Create Standard IO Block");
  285.    InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
  286.    if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
  287.    
  288.    InputBlock->io_Command = (long) function;
  289.    InputBlock->io_Data    = (APTR) vScreenData->HandlerInfo;
  290.    if (status = DoIO(InputBlock)) DoExit("Error from DoIO:  %ld",status);
  291.  
  292.    CloseDevice(InputBlock); InputDevice = FALSE;
  293.    DeleteStdIO(InputBlock); InputBlock = NULL;
  294.    DeletePort(InputPort);   InputPort = NULL;
  295. }
  296.  
  297.  
  298. /*
  299.  *  SetVectors()
  300.  *
  301.  *  Call SetFunction() to replace the library vectores for the routines that
  302.  *  we need to trap.  Use the routines that the handler has supplied (they
  303.  *  were passed to us in the vScreenData structure).  Save the old vectors
  304.  *  in the vScreenData strucutre so we can replace them later.  Set the 
  305.  *  jump addresses so that the stub routines can call the old vectors.
  306.  *  I Know this is a kludge, and is a form of self-modifying code, but I
  307.  *  can't figure out a better method.  The JSR (Ax) is only good when there
  308.  *  is a free A register, which is not always the case.
  309.  */
  310.  
  311. void SetVectors()
  312. {
  313.    var(OldCloseScreen) =
  314.        SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
  315.    var(CloseScreenJmpTarget)[-1] = (long) var(OldCloseScreen);
  316.  
  317.    var(OldBuildSysRequest) =
  318.        SetFunction(IntuitionBase,&LVOBuildSysRequest,var(aBuildSysRequest));
  319.    var(BuildSysRequestJmpTarget)[-1] = (long) var(OldBuildSysRequest);
  320.  
  321.    var(OldAutoRequest) =
  322.       SetFunction(IntuitionBase,&LVOAutoRequest,var(aAutoRequest));
  323.    var(AutoRequestJmpTarget)[-1] = (long) var(OldAutoRequest);
  324.  
  325.    var(OldLoadView) = SetFunction(GfxBase,&LVOLoadView,var(aLoadView));
  326.    var(LoadViewJmpTarget)[-1] = (long) var(OldLoadView);
  327.  
  328.    var(OldMoveSprite) = SetFunction(GfxBase,&LVOMoveSprite,var(aMoveSprite));
  329.    var(MoveSpriteJmpTarget)[-1] = (long) var(OldMoveSprite);
  330. }
  331.  
  332.  
  333. /*
  334.  *  UnSetVectors()
  335.  *
  336.  *  Put back the old jump vectors for the routines that we replaced.
  337.  *  Make sure that no one else has replced them behind our backs, however.
  338.  *  If they are not the same way we left them, return an error status.
  339.  */
  340.  
  341. int UnSetVectors()
  342. {
  343.    long NewCloseScreen,NewBuildSysRequest,NewAutoRequest,
  344.         NewLoadView,NewMoveSprite;
  345.    int status = TRUE;
  346.  
  347.    NewCloseScreen =
  348.       SetFunction(IntuitionBase,&LVOCloseScreen,var(OldCloseScreen));
  349.    NewBuildSysRequest =
  350.       SetFunction(IntuitionBase,&LVOBuildSysRequest,var(OldBuildSysRequest));
  351.    NewAutoRequest =
  352.       SetFunction(IntuitionBase,&LVOAutoRequest,var(OldAutoRequest));
  353.    NewLoadView   = SetFunction(GfxBase,&LVOLoadView,var(OldLoadView));
  354.    NewMoveSprite = SetFunction(GfxBase,&LVOMoveSprite,var(OldMoveSprite));
  355.  
  356.    if (NewCloseScreen     != (long) var(aCloseScreen) ||
  357.        NewBuildSysRequest != (long) var(aBuildSysRequest) ||
  358.        NewAutoRequest     != (long) var(aAutoRequest) ||
  359.        NewLoadView        != (long) var(aLoadView) ||
  360.        NewMoveSprite      != (long) var(aMoveSprite))
  361.    {
  362.       SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
  363.       SetFunction(IntuitionBase,&LVOBuildSysRequest,NewBuildSysRequest);
  364.       SetFunction(IntuitionBase,&LVOAutoRequest,NewAutoRequest);
  365.       SetFunction(GfxBase,&LVOLoadView,NewLoadView);
  366.       SetFunction(GfxBase,&LVOMoveSprite,NewMoveSprite);
  367.       status = FALSE;
  368.    }
  369.    return(status);
  370. }
  371.  
  372.  
  373. /*
  374.  *  main()
  375.  *
  376.  *  Look for the vScreen port.
  377.  *  If one does not exist then vScreen is not currently active, so
  378.  *    open the intuition and graphics libraries.
  379.  *    Parse the command-line arguments to get the width, height, and screen.
  380.  *    Load the handler code, and check its version.
  381.  *    Create the named port used to store information about the handler.
  382.  *    Setup some of the variables needed by the handler, and save a pointer
  383.  *      to the handler data in the named port.
  384.  *    Try to enlarge the size of the screen bitmap, and set more variables.
  385.  *    Add the input handler into the input chain.
  386.  *    SetFunction the neede vectors.  At this point vScreen is active.
  387.  *    Print a message that reports the version numbers.
  388.  *  Otherwise (the port already exists, so vScreen already is active)
  389.  *    Get the pointer to the vScreenData structure from the port.
  390.  *    If they user had supplied arguments, tell him vScreen already is running.
  391.  *    Try to unset the routines we replaced earlier.
  392.  *    If the vectors we removed successfully then
  393.  *      Remove the input handler.
  394.  *      Restore the screen to its original size.
  395.  *      Delete the (no-longer-needed) named port.
  396.  *      Unload the handler code.
  397.  *      Tell the user that the code is removed.
  398.  *      Close the libraries (note that these remained open between calls 
  399.  *        to vScreen, while the handler was active).
  400.  *    Otherwise (we could not replce the function vectors)
  401.  *      Report the problem, and leave the handler running.
  402.  */
  403.  
  404. void main(argc,argv)
  405. int argc;
  406. char *argv[];
  407. {
  408.    NamedPort = FindPort(PORTNAME);
  409.    if (NamedPort == NULL)
  410.    {
  411.       CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
  412.       CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
  413.  
  414.       ParseArguments(argc,argv);
  415.       LoadHandler();
  416.       if ((NamedPort = CreateNonSigPort(var(PortName),0L)) == NULL)
  417.          DoExit("Can't Create Message Port '%s'",var(PortName));
  418.  
  419.       SetVariables(NamedPort);
  420.       Enlarged = EnlargeScreen();
  421.       TellInputDevice(IND_ADDHANDLER);
  422.       SetVectors();
  423.  
  424.       printf("%s v%d.%d.%d Installed\n",program,
  425.          var(MajVers),var(MinVers),var(LoadVers));
  426.    } else {
  427.       GetVariables(NamedPort);
  428.       if (argc > 1)
  429.       {
  430.          printf("%s already active on screen '%s'\n",program,VScreen->Title);
  431.       } else {
  432.          if (UnSetVectors())
  433.          {
  434.             TellInputDevice(IND_REMHANDLER);
  435.             RestoreScreen();
  436.             DeleteNonSigPort(NamedPort);
  437.             UnLoadSeg(var(Segment));
  438.             printf("%s Removed\n",program);
  439.             CloseLibrary(IntuitionBase);
  440.             CloseLibrary(GfxBase);
  441.          } else {
  442.             printf("SetFunction vectors have been changed!\n");
  443.             printf("%s Not Removed\n",program);
  444.          }
  445.       }
  446.    }
  447. }
  448.